#npm datatables example
Explore tagged Tumblr posts
Text
Install Datatable via npm in Laravel 8
Install Datatable via npm in Laravel 8
Hello everyone, in this article, we will see how we can install datatable using NPM in Laravel 8.Before moving forward let’s know a bit about NPM and Jquery Datatables. All about NPM The name npm (Node Package Manager) stems from when npm first was created as a package manager for Node.js.All npm packages are defined in files called package.json.The content of package.json must be written…
View On WordPress
#angular datatables npm#datatables bootstrap npm#export datatable to excel in laravel#laravel 7 datatables#laravel 8 datatables#laravel mix datatables#npm datatables example#npm uninstall datatables
1 note
·
View note
Text
Creating Ionic Datatable With ngx-datatable
If you are working with a lot of data you might have encountered the problem of presenting this data in an Excel like way inside your Ionic app. Although the datatable pattern is not always the most recommended for mobile apps, especially in times of PWAs having the ability to create a table within your Ionic app is a great alternative.
Inside this tutorial we will use the ngx-datatable package which was made for Angular apps, so we can perfectly use this inside our Ionic app as well!
But as you can see from the gif above, using this pattern on small devices is problematic but let’s talk about the good things for now and see how to add it to our app.
Adding ngx-datatable to your Ionic Project
Like always we start with a blank Ionic app and install the datatable packe to our app, so go ahead and run:
ionic start dataTable blank
cd dataTable
npm i @swimlane/ngx-datatable
ionic g page table
We’ve also created a new page which comes with a module file, because the initial page doesn’t. Therefore, go ahead and remove all references to the HomePage from your module file and then set a new entry point for our app inside the app/app.component.ts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = 'TablePage';
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
});
}
}
The ngx-datatable comes with some predefined styling we can use, but first we need to make sure the styling and an additional font is copied over to our build folder. Therefore, add a new block to your package.json
"config": {
"ionic_sass": "./config/sass.config.js",
"ionic_copy": "./config/copy.config.js"
}
We've changed the copy times already in many other articles, and the only change we really need is to copy over the fonts in an additional task. Create the folder and new file at config/copy.config.js and insert everything from the regular Ionic copy script plus a block which copies over the fonts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = {
copyAssets: {
src: ['/assets/**/*'],
dest: '/assets'
},
copyIndexContent: {
src: ['/index.html', '/manifest.json', '/service-worker.js'],
dest: ''
},
copyFonts: {
src: ['/node_modules/ionicons/dist/fonts/**/*', '/node_modules/ionic-angular/fonts/**/*'],
dest: '/assets/fonts'
},
copyPolyfills: {
src: ['/node_modules/ionic-angular/polyfills/polyfills.js'],
dest: ''
},
copyNgxFont: {
src: ['/node_modules/@swimlane/ngx-datatable/release/assets/fonts/data-table.ttf',
'/node_modules/@swimlane/ngx-datatable/release/assets/fonts/data-table.woff'],
dest: '/fonts'
}
}
For the second special file, create another new file at config/sass.config.js. For this file, copy the contents of the original file (which is pretty long) from /node_modules/@ionic/app-scripts/config/sass.config.js.
Then, search for the includePaths block and add one line to it at the end like this:
includePaths: [
'node_modules/ionic-angular/themes',
'node_modules/ionicons/dist/scss',
'node_modules/ionic-angular/fonts',
'node_modules/@swimlane/ngx-datatable/release'
],
Now both the font and styling of the package is copied to our build folder and we can use it easily! To make the styling available to our app we also need to import both available styles, so change your app/app.scss to:
@import 'themes/bootstrap';
@import 'themes/dark';
@import 'assets/icons';
That’s all for the integration, now to the actual usage!
Presenting a Basic Table
We start with a super basic example where we’ll display some information in the most easy way possible.
To use this package inside your pages you first need to add it to the imports of the module, in our case we need to change the pages/table/table.module.ts to this:
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TablePage } from './table';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
@NgModule({
declarations: [
TablePage,
],
imports: [
IonicPageModule.forChild(TablePage),
NgxDatatableModule
],
})
export class TablePageModule {}
Next we need some data which I’ve copied from one of their examples.
Additionally I’ve already incorporated a little switch so you can change the theme of your datatable from bootstrap to dark so you can see both of them in action!
There’s not much to it right now, so change your pages/table/table.ts to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
@IonicPage()
@Component({
selector: 'page-table',
templateUrl: 'table.html',
})
export class TablePage {
// https://ift.tt/2L4O4cI
rows = [
{
"name": "Ethel Price",
"gender": "female",
"age": 22
},
{
"name": "Claudine Neal",
"gender": "female",
"age": 55
},
{
"name": "Beryl Rice",
"gender": "female",
"age": 67
},
{
"name": "Simon Grimm",
"gender": "male",
"age": 28
}
];
tablestyle = 'bootstrap';
constructor(public navCtrl: NavController, public navParams: NavParams) { }
switchStyle() {
if (this.tablestyle == 'dark') {
this.tablestyle = 'bootstrap';
} else {
this.tablestyle = 'dark';
}
}
}
We wanted to build the most basic version of a table first, so here it is! We only add one extra button to change our table style, and inside the view we craft the table.
This table needs rows which are the datasource and even the additional attributes I’ve adde might be obsolete but are needed to present the table in an appealing way on a mobile device.
Inside the table you then define columns for your values, in our case three of them which will look up the value of their name. The name doesn’t have to be the key inside the array, but more on this later.
The table will now iterate over your data and create the according rows and columns, so for now change the pages/table/table.html to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ion-header>
<ion-navbar color="dark">
<ion-title>ngx-Table</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="switchStyle()">
<ion-icon name="bulb"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ngx-datatable class="fullscreen" [ngClass]="tablestyle" [rows]="rows" [columnMode]="'force'" [sortType]="'multi'" [reorderable]="false">
<ngx-datatable-column name="Name"></ngx-datatable-column>
<ngx-datatable-column name="Gender"></ngx-datatable-column>
<ngx-datatable-column name="Age"></ngx-datatable-column>
</ngx-datatable>
</ion-content>
The result of this simple is what you can see below.
Kinda nice for just a few lines of HTML that create everything from a given datasource, right?
Advanced Ionic Datatable
Let’s build a more sophisticated example with some reordering mechanism, additional row buttons and special styling.
For this, we start by adding a few functions to our class. To determine a special class that get’s added to a row we define the getRowClass() function that checks if the dataset of the row is a male or female person. In both cases we return the name of a CSS class that we will define later.
When we open a row, we simply present an alert with basic information gathered from the row to show how everyhting works.
Finally we also have some summary functions that can be used to display a summary row inside your table. Most of the time the default summary for your column won’t work so with these functions you can write your own logic for creating the sum or average or whatever you want to display!
In our case we present the sum of male/female persons as well as the average age of our persons.
Go ahead and add the new functions to your pages/table/table.ts like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, AlertController } from 'ionic-angular';
@IonicPage()
@Component({
selector: 'page-table',
templateUrl: 'table.html',
})
export class TablePage {
// https://ift.tt/2L4O4cI
rows = [
{
"name": "Ethel Price",
"gender": "female",
"age": 22
},
{
"name": "Claudine Neal",
"gender": "female",
"age": 55
},
{
"name": "Beryl Rice",
"gender": "female",
"age": 67
},
{
"name": "Simon Grimm",
"gender": "male",
"age": 28
}
];
tablestyle = 'bootstrap';
constructor(public navCtrl: NavController, public navParams: NavParams, private alertCtrl: AlertController) { }
switchStyle() {
if (this.tablestyle == 'dark') {
this.tablestyle = 'bootstrap';
} else {
this.tablestyle = 'dark';
}
}
getRowClass(row) {
return row.gender == 'male' ? 'male-row' : 'female-row';
}
open(row) {
let alert = this.alertCtrl.create({
title: 'Row',
message: `${row.name} is ${row.age} years old!`,
buttons: ['OK']
});
alert.present();
}
//
// Summary Functions
//
genderSummary(values) {
let male = values.filter(val => val == 'male').length;
let female = values.filter(val => val == 'female').length;
return `${male} / ${female}`;
}
ageSummary(values) {
return values.reduce((a, b) => a+b, 0) / values.length;
}
}
Now we also need to add some changes to the view in order to make use of the new functionality we’ve implemented. First of all we add the CSS that is needed to customize rows based on the gender, so change your pages/table/table.scss to:
page-table {
.male-row {
background-color: green !important;
}
.female-row {
background-color: red !important;
}
}
The last missing piece now is the view which needs to be changed for our custom columns. We’ve previously seen basic columns, but we can also have more control about the header, the used value for the column or which summary function should be used.
There are quite a few options you can set for both the table and columns, so for all the information check out the official documentation which also contains examples for almost everything the package offers!
Let’s change the code and talk about a few elements afterwards, so open your pages/table/table.html and change it to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<ion-header>
<ion-navbar color="dark">
<ion-title>ngx-Table</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="switchStyle()">
<ion-icon name="bulb"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ngx-datatable class="fullscreen" [ngClass]="tablestyle" [rows]="rows" [columnMode]="'force'" [sortType]="'multi'" [reorderable]="false"
[rowHeight]="50" [rowClass]="getRowClass" [summaryRow]="true" [summaryPosition]="'top'">
<ngx-datatable-column prop="name" [resizeable]="false">
<ng-template let-column="column" ngx-datatable-header-template let-sort="sortFn">
<span (click)="sort()">Special User</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
{{ value }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Gender" [summaryFunc]="genderSummary.bind(this)"></ngx-datatable-column>
<ngx-datatable-column name="Age" [summaryFunc]="ageSummary.bind(this)"></ngx-datatable-column>
<ngx-datatable-column name="id" [resizeable]="false">
<ng-template ngx-datatable-header-template>
Action
</ng-template>
<ng-template let-row="row" ngx-datatable-cell-template>
<button ion-button small outline color="light" (click)="open(row)">Details</button>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</ion-content>
Here is a bit more information about what we’ve used and what it does:
let-sort=”sortFn”: Use the default alpha numeric ordering mechanism for this column
prop: Use the specified key inside the datasource to lookup the value for the column
summaryFunc: Use a special summary function for the whole column
.bind(this): Not needed here but makes this available inside the function called!
let-value=”value”: Makes the value of the column available as value
let-row=”row”: Make the whole row object available inside the column
As said before, there’s really a lot you can customize and some elements won’t work that well together. In my testing, the now applied summary function actually breaks the reordering mechanism, but I’m sure there is some fix for that issue as well.
Conclusion
Overall you should be careful when you use a table inside a mobile app, but if you decide you need one the ngx-datatable is an awesome package that offers a lot of options to customize how your data is presented!
You can also find a video version of this article below.
youtube
Get the free 7 day Ionic Crash Course to learn how to:
Get started with Ionic
Build a Tab Bar navigation
Make HTTP calls to a REST API
Store Data inside your app
Use Cordova plugins
Style your Ionic app
The course is free, so there's nothing you can lose!
Success! Now check your email to confirm your subscription.
via Devdactic https://ift.tt/2NHzXfh
0 notes
Text
Laravel + Vue.js AdminPanel Generator
News / May 11, 2018
Laravel + Vue.js AdminPanel Generator
Laravel and Vue.js are often used together. With more tools on these technologies are released, here’s one of them – presenting to you Vue+Laravel Admin Panel Generator.
Disclaimer: I’m the founder and one of the developers of this tool, and also Laravel-only generator QuickAdminPanel, but the goal in this article is not only to present you the product, but explain what it generates, and how Vue + Laravel work together. Also, you will find an example project with source available on Github.
How does the generator work?
For those who prefer video, here’s a quick demo:
youtube
Now, let’s look at it with more details.
Step 1. You create your panel without coding, just adding menu items and fields.
Step 2. At any point, you can view the generated code, file by file.
Step 3. Then you download the code and install it – locally or on your remote server, with these commands:
composer install php artisan key:generate php artisan migrate --seed php artisan passport:install
Of course, your .env file should be configured at that point.
And then, on the front-end:
npm install npm run dev
Step 4. That’s it; you have your panel.
Step 5. The most important thing: you can change the code however you want, it’s pure Laravel+Vue, without our generator’s package as a dependency. That’s the main difference from packages like Voyager or Laravel Backpack (which are both excellent, by the way!).
What are we generating – structure of the project
After you download the project, you see something like this:
Generated Code: Back-end Laravel
Let’s first analyze the back-end Laravel part, which serves as API:
Here’s routes/api.php file:
Route::group(['prefix' => '/v1', 'middleware' => ['auth:api'], 'namespace' => 'Api\V1', 'as' => 'api.'], function () { Route::post('change-password', 'ChangePasswordController@changePassword')->name('auth.change_password'); Route::apiResource('roles', 'RolesController'); Route::apiResource('users', 'UsersController'); Route::apiResource('companies', 'CompaniesController'); Route::apiResource('employees', 'EmployeesController'); });
You can see apiResource for every CRUD, and also one separate POST for changing the password.
Controllers are namespaces under Api/V1, so here’s our app/Http/Controllers/Api/V1/CompaniesController.php:
namespace App\Http\Controllers\Api\V1; use App\Company; use App\Http\Controllers\Controller; use App\Http\Resources\Company as CompanyResource; use App\Http\Requests\Admin\StoreCompaniesRequest; use App\Http\Requests\Admin\UpdateCompaniesRequest; use Illuminate\Http\Request; class CompaniesController extends Controller { public function index() { return new CompanyResource(Company::with([])->get()); } public function show($id) { $company = Company::with([])->findOrFail($id); return new CompanyResource($company); } public function store(StoreCompaniesRequest $request) { $company = Company::create($request->all()); return (new CompanyResource($company)) ->response() ->setStatusCode(201); } public function update(UpdateCompaniesRequest $request, $id) { $company = Company::findOrFail($id); $company->update($request->all()); return (new CompanyResource($company)) ->response() ->setStatusCode(202); } public function destroy($id) { $company = Company::findOrFail($id); $company->delete(); return response(null, 204); } }
We have a typical resourceful Controller, with one exception – Resources classes, which have been available since Laravel 5.5.
In our case, every resource is a simple conversion to an array, here’s a file app/Http/Resources/Company.php
namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class Company extends JsonResource { /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return parent::toArray($request); } }
But you can extend it, adding your logic on top – see more examples here and here.
Finally, Laravel Passport protects all the routes – when installing the project, you need to run this:
php artisan passport:install
As an overall back-end result, every Controller is responsible for that specific CRUD operations called to the API, from Vue.js front-end.
Generated Code: Front-end Vue.js
Now, let’s take a look at front-end part. The main file for this is resources/client/assets/js/app.js, where we initiate the Vue and some libraries:
// ... window.Vue = require('vue') Vue.prototype.$eventHub = new Vue() import router from './routes' import store from './store' import Datatable from 'vue2-datatable-component' import VueAWN from 'vue-awesome-notifications' import vSelect from 'vue-select' import datePicker from 'vue-bootstrap-datetimepicker' import VueSweetalert2 from 'vue-sweetalert2' import 'eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.css' Vue.use(Datatable) Vue.use(VueAWN, { position: 'top-right' }) Vue.use(datePicker) Vue.use(VueSweetalert2) Vue.component('back-buttton', require('./components/BackButton.vue')) Vue.component('bootstrap-alert', require('./components/Alert.vue')) Vue.component('event-hub', require('./components/EventHub.vue')) Vue.component('vue-button-spinner', require('./components/VueButtonSpinner.vue')) Vue.component('v-select', vSelect) moment.updateLocale(window.app_locale, { week: { dow: 1 } }) const app = new Vue({ data: { relationships: {}, dpconfigDate: { format: window.date_format_moment }, dpconfigTime: { format: window.time_format_moment }, dpconfigDatetime: { format: window.datetime_format_moment, sideBySide: true } }, router, store }).$mount('#app')
Next, every CRUD has its own set of components:
For showing the data table, we’re using vue2-datatable-component – here’s full code of resources/clients/assets/components/cruds/Companies/Index.vue:
<template> <section class="content-wrapper" style="min-height: 960px;"> <section class="content-header"> <h1>Companies</h1> </section> <section class="content"> <div class="row"> <div class="col-xs-12"> <div class="box"> <div class="box-header with-border"> <h3 class="box-title">List</h3> </div> <div class="box-body"> <div class="btn-group"> <router-link :to="{ name: xprops.route + '.create' }" class="btn btn-success btn-sm"> <i class="fa fa-plus"></i> Add new </router-link> <button type="button" class="btn btn-default btn-sm" @click="fetchData"> <i class="fa fa-refresh" :class="{'fa-spin': loading}"></i> Refresh </button> </div> </div> <div class="box-body"> <div class="row" v-if="loading"> <div class="col-xs-4 col-xs-offset-4"> <div class="alert text-center"> <i class="fa fa-spin fa-refresh"></i> Loading </div> </div> </div> <datatable v-if="!loading" :columns="columns" :data="data" :total="total" :query="query" :xprops="xprops" /> </div> </div> </div> </div> </section> </section> </template> <script> import { mapGetters, mapActions } from 'vuex' import DatatableActions from '../../dtmodules/DatatableActions' import DatatableSingle from '../../dtmodules/DatatableSingle' import DatatableList from '../../dtmodules/DatatableList' import DatatableCheckbox from '../../dtmodules/DatatableCheckbox' export default { data() { return { columns: [ { title: '#', field: 'id', sortable: true, colStyle: 'width: 50px;' }, { title: 'Name', field: 'name', sortable: true }, { title: 'Description', field: 'description', sortable: true }, { title: 'Actions', tdComp: DatatableActions, visible: true, thClass: 'text-right', tdClass: 'text-right', colStyle: 'width: 130px;' } ], query: { sort: 'id', order: 'desc' }, xprops: { module: 'CompaniesIndex', route: 'companies' } } }, created() { this.$root.relationships = this.relationships this.fetchData() }, destroyed() { this.resetState() }, computed: { ...mapGetters('CompaniesIndex', ['data', 'total', 'loading', 'relationships']), }, watch: { query: { handler(query) { this.setQuery(query) }, deep: true } }, methods: { ...mapActions('CompaniesIndex', ['fetchData', 'setQuery', 'resetState']), } } </script> <style scoped> </style>
Quite a lot of code, isn’t it? Of course, it could be more straightforward, but we tried to follow the official documentation and best practices, generating code for the cases that could be extended for bigger projects.
Next, we can take a look at Create.vue:
<template> <section class="content-wrapper" style="min-height: 960px;"> <section class="content-header"> <h1>Companies</h1> </section> <section class="content"> <div class="row"> <div class="col-xs-12"> <form @submit.prevent="submitForm"> <div class="box"> <div class="box-header with-border"> <h3 class="box-title">Create</h3> </div> <div class="box-body"> <back-buttton></back-buttton> </div> <bootstrap-alert /> <div class="box-body"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" name="name" placeholder="Enter Name" :value="item.name" @input="updateName" > </div> <div class="form-group"> <label for="description">Description</label> <textarea rows="3" class="form-control" name="description" placeholder="Enter Description" :value="item.description" @input="updateDescription" > </textarea> </div> </div> <div class="box-footer"> <vue-button-spinner class="btn btn-primary btn-sm" :isLoading="loading" :disabled="loading" > Save </vue-button-spinner> </div> </div> </form> </div> </div> </section> </section> </template> <script> import { mapGetters, mapActions } from 'vuex' export default { data() { return { // Code... } }, computed: { ...mapGetters('CompaniesSingle', ['item', 'loading']) }, created() { // Code ... }, destroyed() { this.resetState() }, methods: { ...mapActions('CompaniesSingle', ['storeData', 'resetState', 'setName', 'setDescription']), updateName(e) { this.setName(e.target.value) }, updateDescription(e) { this.setDescription(e.target.value) }, submitForm() { this.storeData() .then(() => { this.$router.push({ name: 'companies.index' }) this.$eventHub.$emit('create-success') }) .catch((error) => { console.error(error) }) } } } </script> <style scoped> </style>
Edit and Show components for the CRUD are pretty similar, so won’t discuss them here.
In addition to that Vue code, there are many small details and helpers like Sweet Alert, Notifications, Datepickers, and setting/getting relationships data for the forms. I guess I will leave it for you to analyze.
Notice: The choice of Vue.js libraries is pretty subjective, and it was the most challenging part of the project – to choose the Vue libraries to trust. Ecosystem still lacks standards, or 100% trusted open-source – a lot of movement in the market, some libraries are better supported than others. So it’s always hard to guess, and the best libraries will probably change with time, or new ones will appear.
That’s the end of a quick overview of Vue+Laravel QuickAdminPanel, try it out here: https://vue.quickadminpanel.com
Finally, here’s the source of a demo-project with two CRUDs: Companies and Customers.
I hope our generator will not only save you time on writing code but also show you how Vue can work with Laravel. Our way of structuring this code is not the only way, and you can structure your code differently, but we tried our best to stick to standards.
via Laravel News https://ift.tt/2wzPFV6
0 notes